const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const crypto = require('crypto');

/**
 * 生成JWT令牌
 * @param {Object} payload - 令牌载荷
 * @param {string} secret - 密钥
 * @param {string} expiresIn - 过期时间
 * @returns {string} JWT令牌
 */
const generateToken = (payload, secret = process.env.JWT_SECRET, expiresIn = process.env.JWT_EXPIRES_IN) => {
  return jwt.sign(payload, secret, { expiresIn });
};

/**
 * 验证JWT令牌
 * @param {string} token - JWT令牌
 * @param {string} secret - 密钥
 * @returns {Object} 解码后的载荷
 */
const verifyToken = (token, secret = process.env.JWT_SECRET) => {
  return jwt.verify(token, secret);
};

/**
 * 生成刷新令牌
 * @param {Object} payload - 令牌载荷
 * @returns {string} 刷新令牌
 */
const generateRefreshToken = (payload) => {
  return generateToken(payload, process.env.JWT_REFRESH_SECRET, process.env.JWT_REFRESH_EXPIRES_IN);
};

/**
 * 验证刷新令牌
 * @param {string} token - 刷新令牌
 * @returns {Object} 解码后的载荷
 */
const verifyRefreshToken = (token) => {
  return verifyToken(token, process.env.JWT_REFRESH_SECRET);
};

/**
 * 加密密码
 * @param {string} password - 明文密码
 * @returns {Promise<string>} 加密后的密码
 */
const hashPassword = async (password) => {
  const saltRounds = 12;
  return await bcrypt.hash(password, saltRounds);
};

/**
 * 验证密码
 * @param {string} password - 明文密码
 * @param {string} hashedPassword - 加密后的密码
 * @returns {Promise<boolean>} 验证结果
 */
const comparePassword = async (password, hashedPassword) => {
  return await bcrypt.compare(password, hashedPassword);
};

/**
 * 从请求头中提取Bearer令牌
 * @param {Object} req - Express request object
 * @returns {string|null} JWT令牌
 */
const extractTokenFromHeader = (req) => {
  const authHeader = req.headers.authorization;
  if (authHeader && authHeader.startsWith('Bearer ')) {
    return authHeader.substring(7);
  }
  return null;
};

/**
 * 生成随机字符串
 * @param {number} length - 字符串长度
 * @returns {string} 随机字符串
 */
const generateRandomString = (length = 32) => {
  return crypto.randomBytes(length).toString('hex');
};

/**
 * MD5加密
 * @param {string} text - 待加密文本
 * @returns {string} MD5哈希值
 */
const md5 = (text) => {
  return crypto.createHash('md5').update(text).digest('hex');
};

/**
 * 创建用户Token载荷
 * @param {Object} user - 用户对象
 * @returns {Object} Token载荷
 */
const createUserPayload = (user) => {
  return {
    id: user.id,
    username: user.username,
    nickname: user.nickname,
    role: user.role || 'user'
  };
};

/**
 * Token解析和记录工具
 * @param {Object} req - Express request object
 * @param {string} msg - 日志消息
 * @returns {Object} 解码后的Token
 */
const analyzeAndRecordToken = (req, msg) => {
  const token = extractTokenFromHeader(req);
  if (!token) {
    throw new Error('Token不存在');
  }

  const decoded = verifyToken(token);
  console.log(`${decoded.username || decoded.nickname} ${msg}`);
  return decoded;
};

/**
 * JWT认证中间件
 */
const authenticateToken = async (req, res, next) => {
  const { unauthorized, error: errorResponse } = require('./response');
  const userDao = require('../dao/userDao');

  try {
    const token = extractTokenFromHeader(req);

    if (!token) {
      return unauthorized(res, '未提供访问令牌');
    }

    // 验证token
    const decoded = verifyToken(token);

    // 获取用户信息
    const user = await userDao.findById(decoded.id || decoded.userId);
    if (!user) {
      return unauthorized(res, '用户不存在');
    }

    // 将用户信息添加到请求对象
    req.user = user;
    next();
  } catch (err) {
    if (err.name === 'JsonWebTokenError') {
      return unauthorized(res, '无效的访问令牌');
    } else if (err.name === 'TokenExpiredError') {
      return unauthorized(res, '访问令牌已过期');
    } else {
      console.error('认证中间件错误:', err);
      return errorResponse(res, '服务器内部错误', 500);
    }
  }
};

/**
 * 可选认证中间件（不强制要求登录）
 */
const optionalAuth = async (req, res, next) => {
  const userDao = require('../dao/userDao');

  try {
    const token = extractTokenFromHeader(req);

    if (token) {
      const decoded = verifyToken(token);
      const user = await userDao.findById(decoded.id || decoded.userId);
      if (user) {
        req.user = user;
      }
    }

    next();
  } catch (error) {
    // 可选认证失败时不返回错误，继续执行
    next();
  }
};

module.exports = {
  generateToken,
  verifyToken,
  generateRefreshToken,
  verifyRefreshToken,
  hashPassword,
  comparePassword,
  extractTokenFromHeader,
  generateRandomString,
  md5,
  createUserPayload,
  analyzeAndRecordToken,
  authenticateToken,
  optionalAuth
};
